package com.itxiuyixiu.volunteer.service;

import com.itxiuyixiu.entity.enums.ActivityState;
import com.itxiuyixiu.entity.enums.AuthorityType;
import com.itxiuyixiu.entity.enums.DHUCollage;
import com.itxiuyixiu.entity.mapper.*;
import com.itxiuyixiu.entity.model.*;
import com.itxiuyixiu.tools.security.user.GetUser;
import com.itxiuyixiu.volunteer.common.errors.ServiceException;
import com.itxiuyixiu.volunteer.dto.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author 黄磊
 * @date 2020/5/3
 */
@Slf4j
@Service
public class OrganizationService {
    @Resource
    private AdminReaderMapper adminReaderMapper;
    @Resource
    private OrganizationWriterMapper organizationWriterMapper;
    @Resource
    private OrganizationReaderMapper organizationReaderMapper;
    @Resource
    private ProjectReaderMapper projectReaderMapper;
    @Resource
    private ProjectWriterMapper projectWriterMapper;
    @Resource
    private ActivityWriterMapper activityWriterMapper;
    @Resource
    private ActivityReaderMapper activityReaderMapper;
    @Resource
    private StudentReaderMapper studentReaderMapper;
    @Resource
    private StudentWriterMapper studentWriterMapper;
    @Resource
    private EnterListWriterMapper enterListWriterMapper;
    @Resource
    private EnterListReaderMapper enterListReaderMapper;
    @Resource
    private TempStudentReaderMapper tempStudentReaderMapper;
    @Resource
    private TempStudentWriterMapper tempStudentWriterMapper;

    public Organization findOrganizationMessage() {
        String name = GetUser.getUserName();
        Optional<Organization> organizationOptional = organizationReaderMapper.findOrganizationByAdminUsername(name);
        return organizationOptional.orElse(null);
    }

    public void modifyOrganizationMessage(OrganizationModifyMessageParam organizationDto) {
        String userName = GetUser.getUserName();
        Organization organization = getOrganization();
        organization.setOrgName(organizationDto.getOrgName());
        organization.setOrgDetail(organizationDto.getOrgDetail());
        organization.setOrgMember(organizationDto.getOrgMember());
        organization.setOrgContact(organizationDto.getOrgContact());
        organization.setAcademy(organizationDto.getAcademy());
        organization.setOrgImage(organizationDto.getOrgImage());
        organizationWriterMapper.modifyOrganizationById(organization);
        log.debug("管理员" + organization.getAdminId() + "成功修改志愿者组织" + organization.getOrganizationId() + "的信息");
    }

    public int saveProject(ProjectSaveParam projectDto) {
        String userName = GetUser.getUserName();
        Organization organization = getOrganization();
        Project project = new Project();
        project.setProjectName(projectDto.getProjectName());
        project.setProjectDetail(projectDto.getProjectDetail());
        project.setProjectImage(projectDto.getProjectImage());
        project.setAdminId(organization.getAdminId());
        project.setOrganizationId(organization.getOrganizationId());
        project.setAdminId(organization.getAdminId());
        projectWriterMapper.saveProject(project);
        log.debug("管理员" + project.getAdminId() + "成功创建志愿者项目" + project.getProjectId() + "的信息");
        return project.getProjectId();
    }

    public List<ProjectView> findAllProject() {
        Organization organization = getOrganization();
        return projectReaderMapper.findAllProjectViewByOrganizationId(organization.getOrganizationId());
    }

    public Project findProjectByProjectId(Integer projectId) {
        Optional<Project> projectOptional = projectReaderMapper.findProjectByProjectId(projectId);
        if (!projectOptional.isPresent()) {
            return null;
        }
        Project project = projectOptional.get();
        if (isAdminIdNotBelongAdmin(project.getAdminId())) {
            return null;
        }
        return project;
    }

    public int modifyProject(int projectId, ProjectModifyMessageParam projectDto) {
        Optional<Project> projectOptional = projectReaderMapper.findProjectByProjectId(projectId);
        if (!projectOptional.isPresent()) {
            return 1;
        }
        Project project = projectOptional.get();
        if (isAdminIdNotBelongAdmin(project.getAdminId())) {
            return 2;
        }
        project.setProjectName(projectDto.getProjectName());
        project.setProjectDetail(projectDto.getProjectDetail());
        project.setProjectImage(projectDto.getProjectImage());
        projectWriterMapper.modifyProjectById(project);
        log.debug("管理员" + project.getAdminId() + "成功修改志愿者项目：" + project.getProjectId() + "的信息");
        return 0;
    }

    public int deleteProject(Integer projectId) {
        Optional<Project> projectOptional = projectReaderMapper.findProjectByProjectId(projectId);
        if (!projectOptional.isPresent()) {
            return 1;
        }
        Project project = projectOptional.get();
        if (isAdminIdNotBelongAdmin(project.getAdminId())) {
            return 2;
        }
        activityWriterMapper.modifyProjectIdNull(project.getProjectId());
        projectWriterMapper.deleteProjectById(project.getProjectId());
        log.debug("管理员" + project.getAdminId() + "成功删除志愿者项目：" + project.getProjectId());
        return 0;
    }

    public int saveActivity(ActivitySaveParam dto) {
        Activity activity = new Activity();
        activity.setActivityName(dto.getActivityName());
        activity.setActivityDetail(dto.getActivityDetail());
        addActivityTime(activity, dto.getStartTime(), dto.getEndTime(), dto.getOutTime());
        activity.setMaxNumber(dto.getMaxNumber());
        activity.setAttention(dto.getAttention());
        activity.setActivityType(dto.getActivityType());
        activity.setActivityAddress(dto.getActivityAddress());
        activity.setServeHours(dto.getServeHours());
        activity.setAcademyLimited(dto.getAcademyLimited());
        activity.setAcademyLimitedList(dto.getAcademyLimitedList());
        activity.setActivityState(ActivityState.AUDITING);
        if (dto.getProjectId() != null) {
            Optional<Project> projectOptional = projectReaderMapper.findProjectByProjectId(dto.getProjectId());
            if (!projectOptional.isPresent()) {
                throw new ServiceException("活动所属的志愿者项目没有找到");
            } else {
                activity.setProjectId(projectOptional.get().getProjectId());
            }
        }
        Organization organization = getOrganization();
        activity.setAdminId(organization.getAdminId());
        activity.setOrganizationId(organization.getOrganizationId());
        activityWriterMapper.saveActivity(activity);
        log.debug("管理员" + organization.getAdminId() + "添加了志愿者活动" + activity.getActivityId());
        return activity.getActivityId();
    }

    public List<ActivityView> findAllActivity() {
        return activityReaderMapper.findAllActivityViewByOrganizationId(getOrganization().getOrganizationId());
    }

    public Activity findActivityByActivityId(Integer activityId) {
        Optional<Activity> activityOptional = activityReaderMapper.findActivityByActivityId(activityId);
        if (!activityOptional.isPresent()) {
            return null;
        }
        Activity activity = activityOptional.get();
        if (isAdminIdNotBelongAdmin(activity.getAdminId())) {
            return null;
        }
        return activity;
    }

    public void modifyActivity(Integer activityId, ActivityModifyMessageParam dto) {
        Optional<Activity> activityOptional = activityReaderMapper.findActivityByActivityId(activityId);
        if (!activityOptional.isPresent()) {
            throw new ServiceException("要修改的志愿者活动信息未找到");
        }
        Activity activity = activityOptional.get();
        if (isAdminIdNotBelongAdmin(activity.getAdminId())) {
            throw new ServiceException("要修改的志愿者活动不属于您");
        }
        activity.setActivityName(dto.getActivityName());
        activity.setActivityDetail(dto.getActivityDetail());
        addActivityTime(activity, dto.getStartTime(), dto.getEndTime(), dto.getOutTime());
        activity.setMaxNumber(dto.getMaxNumber());
        activity.setAttention(dto.getAttention());
        activity.setActivityType(dto.getActivityType());
        activity.setActivityAddress(dto.getActivityAddress());
        activity.setServeHours(dto.getServeHours());
        activity.setAcademyLimited(dto.getAcademyLimited());
        activity.setAcademyLimitedList(dto.getAcademyLimitedList());
        activity.setActivityImages(dto.getActivityImages());
        activityWriterMapper.modifyActivityById(activity);
        log.debug("管理员" + activity.getAdminId() + "修改了志愿者活动" + activity.getActivityId());
    }

    public List<Activity> findAllActivityByProjectId(Integer projectId) {
        return activityReaderMapper.findAllActivityByProjectId(projectId);
    }

    /**
     * 更改志愿者活动状态
     *
     * @param activityId    活动id
     * @param activityState 要更改的状态
     */
    public void modifyActivityState(Integer activityId, ActivityState activityState) {
        Optional<Activity> activityOptional = activityReaderMapper.findActivityByActivityId(activityId);
        if (!activityOptional.isPresent()) {
            throw new ServiceException("活动未找到");
        }
        Activity activity = activityOptional.get();
        if (isAdminIdNotBelongAdmin(activity.getAdminId())) {
            throw new ServiceException("要修改的活动不属于您");
        }
        if (activity.getActivityState().compare(ActivityState.PASSED) < 0) {
            throw new ServiceException("活动尚未通过审核，无法修改状态");
        }
        if (activity.getActivityState().equals(ActivityState.FINISHED)) {
            throw new ServiceException("活动已经完结无法修改活动状态");
        }
        if (activityState.compare(ActivityState.PASSED) < 0) {
            throw new ServiceException("无法进行所要修改的状态");
        }
        if (activityState.equals(ActivityState.FINISHED)) {
            activityWriterMapper.finishActivity(activityId);
            log.debug("管理员" + activity.getAdminId() + "完结了志愿者活动：" + activityState);
        } else {
            activity.setActivityState(activityState);
            activityWriterMapper.modifyActivityById(activity);
            log.debug("管理员" + activity.getAdminId() + "修改了志愿者活动为" + activityState);
        }
    }

    /**
     * 保存学生信息
     * 要求：志愿者组织有上传学生信息权限
     * 只有当志愿者组织为东华大学时可以使用academy属性，其他有上传权限的组织只能上传于自己同学院的信息
     *
     * @param dto 学生信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveStudent(StudentSaveParam dto) {
        Admin admin = getAdmin();
        if (!admin.getAuthorities().contains(AuthorityType.UPLOAD_STUDENT_MESSAGE)) {
            throw new ServiceException("您没有上传学生信息的权限");
        }
        if (studentReaderMapper.existStudentByStudentId(dto.getStudentId())) {
            throw new ServiceException("学号已经存在于数据库中");
        }
        Organization organization = getOrganization();
        if (!organization.getAcademy().equals(DHUCollage.DHU) && !organization.getAcademy().equals(dto.getAcademy())) {
            throw new ServiceException("您只能上传自己学院学生信息");
        }
        Student student = new Student();
        student.setStudentId(dto.getStudentId());
        student.setStudentName(dto.getStudentName());
        student.setSex(dto.getSex());
        student.setStudentContact(dto.getStudentContact());
        student.setAcademy(dto.getAcademy());
        checkTempStudentPass(student);
        studentWriterMapper.saveStudent(student);
        log.debug("管理员" + admin.getAdminId() + "添加了学生信息SId—" + student.getSId());
    }

    /**
     * 查询学院所有学生（只有校级有上传权限的组织可以查看所有，校级组织只有查看自己学院的）
     * 权限：有UPLOAD_STUDENT_MESSAGE权限
     *
     * @return 学生信息
     */
    public List<Student> findAllStudent() {
        Admin admin = getAdmin();
        if (!admin.getAuthorities().contains(AuthorityType.UPLOAD_STUDENT_MESSAGE)) {
            throw new ServiceException("您无权查看学生信息");
        }
        Organization organization = getOrganization();
        return studentReaderMapper.findAllStudent().stream().filter(e -> organization.getAcademy().equals(DHUCollage.DHU) || e.getAcademy().equals(organization.getAcademy())).collect(Collectors.toList());
    }

    /**
     * 查询学院学生（只有校级有上传权限的组织可以查看所有）
     * 权限：有UPLOAD_STUDENT_MESSAGE权限
     *
     * @return 学生信息
     */
    public Optional<Student> findStudentBySId(Integer sId) {
        Admin admin = getAdmin();
        if (!admin.getAuthorities().contains(AuthorityType.UPLOAD_STUDENT_MESSAGE)) {
            throw new ServiceException("您无权查看学生信息");
        }
        return studentReaderMapper.findStudentBySId(sId);
    }

    /**
     * 修改学生信息
     *
     * @param sId 学生表主键
     * @param dto 学生信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void modifyStudent(Integer sId, StudentModifyMessageParam dto) {
        Admin admin = getAdmin();
        if (!admin.getAuthorities().contains(AuthorityType.UPLOAD_STUDENT_MESSAGE)) {
            throw new ServiceException("您无权查看学生信息");
        }
        Optional<Student> studentOptional = studentReaderMapper.findStudentBySId(sId);
        if (!studentOptional.isPresent()) {
            throw new ServiceException("学生不存在");
        }
        Student student = studentOptional.get();
        if (!student.getStudentId().equals(dto.getStudentId()) && studentReaderMapper.findStudentByStudentId(dto.getStudentId()).isPresent()) {
            throw new ServiceException("修改后的学号在数据库中已经存在");
        }
        Organization organization = getOrganization();
        if (!organization.getAcademy().equals(DHUCollage.DHU) && !organization.getAcademy().equals(student.getAcademy())) {
            throw new ServiceException("您只能修改自己学院学生信息");
        }
        student.setStudentId(dto.getStudentId());
        student.setStudentName(dto.getStudentName());
        student.setSex(dto.getSex());
        student.setStudentContact(dto.getStudentContact());
        student.setAcademy(student.getAcademy());
        checkTempStudentPass(student);
        studentWriterMapper.modifyStudent(student);
        log.debug("管理员" + admin.getAdminId() + "修改了学生信息SId—" + student.getSId());
    }

    private void checkTempStudentPass(Student student) {
        Optional<TempStudent> tempStudentOptional = tempStudentReaderMapper.findTempStudentByStudentId(student.getStudentId());
        if (!tempStudentOptional.isPresent()) {
            return;
        }
        TempStudent tempStudent = tempStudentOptional.get();
        if (!tempStudent.getStudentName().equals(student.getStudentName())) {
            return;
        }
        student.setUserId(tempStudent.getUserId());
        tempStudentWriterMapper.deleteTempStudentById(tempStudent.getTempStudentId());
    }

    /**
     * 查询正在申请学生认证的学生
     *
     * @return 申请认证的学生
     */
    public List<TempStudent> findAllTempStudent() {
        Admin admin = getAdmin();
        if (!admin.getAuthorities().contains(AuthorityType.UPLOAD_STUDENT_MESSAGE)) {
            throw new ServiceException("您无权查看学生信息");
        }
        Organization organization = getOrganization();
        return tempStudentReaderMapper.findAllTempStudent().stream().filter(e -> organization.getAcademy().equals(DHUCollage.DHU) || e.getAcademy().equals(organization.getAcademy())).collect(Collectors.toList());
    }

    /**
     * 通过学生认证
     *
     * @param tempStudentId 认证的学生id
     * @param pass          是否通过认证
     */
    @Transactional(rollbackFor = Exception.class)
    public void passTempStudent(Integer tempStudentId, boolean pass) {
        Admin admin = getAdmin();
        if (!admin.getAuthorities().contains(AuthorityType.UPLOAD_STUDENT_MESSAGE)) {
            throw new ServiceException("您无权认证学生信息");
        }
        Optional<TempStudent> tempStudentOptional = tempStudentReaderMapper.findTempStudentByTempStudentId(tempStudentId);
        if (!tempStudentOptional.isPresent()) {
            throw new ServiceException("要认证的学生学生不存在");
        }
        TempStudent tempStudent = tempStudentOptional.get();
        if (studentReaderMapper.findStudentByUserId(tempStudent.getUserId()).isPresent()) {
            tempStudentWriterMapper.deleteTempStudentById(tempStudent.getTempStudentId());
            throw new ServiceException("用户已经认证了其他学生，本次认证无效，本认证信息已被删除");
        }
        if (studentReaderMapper.findStudentByStudentId(tempStudent.getStudentId()).isPresent()) {
            throw new ServiceException("学生库中已经存在了此学生，本次认证无效，本认证信息已被删除");
        }
        if (!pass) {
            tempStudentWriterMapper.deleteTempStudentById(tempStudent.getTempStudentId());
            return;
        }
        Student student = new Student();
        student.setStudentId(tempStudent.getStudentId());
        student.setStudentName(tempStudent.getStudentName());
        student.setSex(tempStudent.getSex());
        student.setStudentContact(tempStudent.getStudentContact());
        student.setAcademy(tempStudent.getAcademy());
        student.setUserId(tempStudent.getUserId());
        studentWriterMapper.saveStudent(student);
        log.debug("管理员" + admin.getAdminId() + "通过了学生认证请求studentId—" + student.getStudentId());
        tempStudentWriterMapper.deleteTempStudentById(tempStudent.getTempStudentId());
    }

    /**
     * 查询某一活动的所有参与者
     *
     * @param activityId 活动id
     * @return 所有参与这一活动的参与者信息
     */
    public List<EnterListView> findAllEnterListByActivityId(Integer activityId) {
        return enterListReaderMapper.findAllEnterListViewByActivityId(activityId);
    }

    public Optional<EnterListView> findEnterListById(Integer enterId) {
        return enterListReaderMapper.findEnterListViewById(enterId);
    }

    /**
     * 修改活动参与记录
     *
     * @param dto 要修改的信息
     * @return 修改状态 {
     * 0 - 成功修改活动参与记录
     * 1 - 要修改的记录不存在
     * 2 - 要修改的活动参与记录不属于您
     * }
     */
    public int modifyEnterList(Integer enterId, EnterListModifyMessageParam dto) {
        Admin admin = getAdmin();
        Optional<EnterList> enterListOptional = enterListReaderMapper.findEnterListById(enterId);
        if (!enterListOptional.isPresent()) {
            return 1;
        }
        EnterList enterList = enterListOptional.get();
        if (isActivityNotBelongUser(enterList.getActivityId())) {
            return 2;
        }
        enterList.setEnterDetail(dto.getEnterDetail());
        enterList.setEnterHours(dto.getEnterHours());
        enterListWriterMapper.modifyEnterListById(enterList);
        log.debug("管理员" + admin.getAdminId() + "修改了活动参与记录，enterId-" + enterList.getEnterId());
        return 0;
    }

    /**
     * 删除活动参与者
     *
     * @param enterId 要删除的参与者表主键的id
     * @return 删除状态 {
     * 0 - 成功删除活动参与者
     * 1 - 要删除的信息不存在
     * 2 - 要删除的信息不属于您
     * }
     */
    public int deleteEnterList(Integer enterId) {
        Admin admin = getAdmin();
        Optional<EnterList> enterListOptional = enterListReaderMapper.findEnterListById(enterId);
        if (!enterListOptional.isPresent()) {
            return 1;
        }
        EnterList enterList = enterListOptional.get();
        if (isActivityNotBelongUser(enterList.getActivityId())) {
            return 2;
        }
        enterListWriterMapper.deleteEnterListBySIdAndActivityId(enterList.getSId(), enterList.getActivityId());
        log.debug("管理员" + admin.getAdminId() + "删除了一条活动参与记录");
        return 0;
    }

    /**
     * 向活动中添加开始时间、结束时间、活动不能退出时间
     *
     * @param activity  活动
     * @param startTime 活动开始时间
     * @param endTime   活动结束时间
     */
    private void addActivityTime(Activity activity, LocalDateTime startTime, LocalDateTime endTime, LocalDateTime outTime) {
        if (outTime.isBefore(LocalDateTime.now())) {
            throw new ServiceException("报名截止时间不能早于现在的时间");
        }

        if (startTime.isBefore(outTime)) {
            throw new ServiceException("活动开始时间不能早于报名截止时间");
        }

        if (endTime.isBefore(startTime)) {
            throw new ServiceException("活动的开始时间不能晚于活动的结束时间");
        }
        activity.setOutTime(outTime);
        activity.setStartTime(startTime);
        activity.setEndTime(endTime);
    }

    /**
     * 查看adminId是否 不属于当前管理员
     *
     * @param adminId 要验证的adminId
     * @return 验证状态（true-不属于当前管理员，false-adminId属于当前管理员）
     */
    private boolean isAdminIdNotBelongAdmin(int adminId) {
        Integer id = adminReaderMapper.findAdminByUsername(GetUser.getUserName()).orElseThrow(() -> new ServiceException("没有找到用户信息")).getAdminId();
        return adminId != id;
    }

    /**
     * 查看活动是否 不属于当前管理员
     *
     * @return 验证状态（true-不属于当前管理员，false-adminId属于当前管理员）
     */
    private boolean isActivityNotBelongUser(int activityId) {
        Integer adminId = adminReaderMapper.findAdminByUsername(GetUser.getUserName()).orElseThrow(() -> new ServiceException("没有找到用户信息")).getAdminId();
        Optional<Activity> activityOptional = activityReaderMapper.findActivityByActivityId(activityId);
        if (!activityOptional.isPresent()) {
            return false;
        }
        Activity activity = activityOptional.get();
        return !activity.getAdminId().equals(adminId);
    }

    /**
     * 获取当前管理员的用户信息
     *
     * @return 当前管理员用户信息
     */
    private Admin getAdmin() {
        return adminReaderMapper.findAdminByUsername(GetUser.getUserName()).orElseThrow(() -> new ServiceException("没有找到当前管理员信息"));
    }

    /**
     * 获取当前管理员的志愿者组织信息
     *
     * @return 当前管理员志愿者组织信息
     */
    private Organization getOrganization() {
        return organizationReaderMapper.findOrganizationByAdminUsername(GetUser.getUserName()).orElseThrow(() -> new ServiceException("获取当前管理员的志愿者组织信息"));
    }
}
